import java.awt.Color;
import java.awt.image.BufferedImage;

import processing.core.PApplet;
import processing.core.PFont;
import processing.core.PImage;

public class Visualizer extends PApplet {
	private Analyser _analyser;
	private int switchNumber;
	private int pixel = 1;

	public Visualizer() {
	}

	public void setup() {
		_analyser = Analyser.getInstance();

		//switchNumber = ((_analyser._pixelCount / 26487)
		//		* _analyser._avarageLengthHead * _analyser._avarageCharacterSub) % 9;

		//switchNumber = 7;
		switchNumber = _analyser._iterationCount;
		
		if (switchNumber == 7) {
			size(_analyser._image.getWidth(), _analyser._image.getHeight(), P3D);
		} else {
			size(_analyser._image.getWidth(), _analyser._image.getHeight());
		}
		background(0);
	}

	public void draw() {
		pixel = _analyser._shortestWordLengthTextArea * _analyser._averageCharacterHead;

		while (width % pixel != 0 || height % pixel != 0) {
			pixel--;
		}

		switch (switchNumber) {
		case 1:
			errorPic(pixel);
			createTextOnGrid();
			break;
		case 2:
			drawCheckedPattern2(pixel);
			createTextOnGrid();
			break;
		case 3:
			drawHorizontalLines(pixel);
			createTextOnGrid();
			break;
		case 4:
			drawVerticalLines(pixel);
			createTextOnGrid();
			break;
		case 5:
			pixelateImage(pixel);
			createTextOnGrid();
			break;
		case 6:
			drawSinCurve();
			createTextOnGrid();
			break;
		case 7:
			drawExplosion(pixel);
			createTextOnGrid();
			break;
		case 8:
			drawTanCurve();
			createTextOnGrid();
			break;
		default:
			drawCheckedPattern(pixel);
			createTextOnGrid();
		}

		noLoop();
	}

	private void drawCheckedPattern(int pixel) {
		Color[] array = _analyser.horizontalLine(pixel);
		int help = 0;

		for (int i = 0; i < height; i = i + pixel) {
			Color c = array[help];
			noStroke();
			double rnd = Math.random() * 255;
			fill(c.getRed(), c.getGreen(), c.getBlue(), (int) rnd);
			rect(0, i, width, pixel);
			help++;
		}

		array = _analyser.verticalLine(pixel);
		help = 0;

		for (int i = 0; i < width; i = i + pixel) {
			Color c = array[help];
			noStroke();
			double rnd = Math.random() * 255;
			fill(c.getRed(), c.getGreen(), c.getBlue(), (int) rnd);
			rect(i, 0, pixel, height);
			help++;
		}
	}

	private void drawCheckedPattern2(int pixel) {
		Color[] arrayH = _analyser.horizontalLine(pixel);
		Color[] arrayV = _analyser.verticalLine(pixel);
		int helpH = 0;
		int helpV = 0;
		Boolean h = true;
		Boolean v = true;
		Color c;

		noStroke();

		for (int x = 0; x < width; x = x + pixel) {
			for (int y = 0; y < height; y = y + pixel) {
				if (h) {
					if (v) {
						c = arrayV[helpV];
					} else {
						c = arrayH[helpH];
					}
				} else {
					if (v) {
						c = arrayH[helpH];
					} else {
						c = arrayV[helpV];
					}
				}
				fill(c.getRed(), c.getGreen(), c.getBlue());
				rect(x, y, pixel, pixel);
				v = !v;
				helpH++;
			}
			h = !h;
			helpH = 0;
			helpV++;
			if (height % 2 == 1) {
				v = !v;
			}
		}
	}

	private void drawHorizontalLines(int pixel) {
		Color[] array = _analyser.horizontalLine(pixel);
		int help = 0;

		for (int i = 0; i < height; i = i + pixel) {
			Color c = array[help];
			noStroke();
			fill(c.getRed(), c.getGreen(), c.getBlue());
			rect(0, i, width, pixel);
			help++;
		}
	}

	private void drawVerticalLines(int pixel) {
		Color[] array = _analyser.verticalLine(pixel);
		int help = 0;

		for (int i = 0; i < width; i = i + pixel) {
			Color c = array[help];
			noStroke();
			fill(c.getRed(), c.getGreen(), c.getBlue());
			rect(i, 0, pixel, height);
			help++;
		}
	}

	private void pixelateImage(int pixel) {
		Color[][] array = _analyser.pixelImage(pixel);
		int helpX = 0;
		int helpY = 0;

		for (int i = 0; i < width; i = i + pixel) {
			for (int j = 0; j < height; j = j + pixel) {
				Color c = array[helpX][helpY];
				helpY++;
				noStroke();
				fill(c.getRed(), c.getGreen(), c.getBlue());
				rect(i, j, pixel, pixel);
			}
			helpX++;
			helpY = 0;
		}
	}

	private void drawSinCurve() {
		Color[] array = _analyser.horizontalLine(1);

		for (int y = 0; y < height; y++) {
			for (int x = 0; x < width; x++) {
				Color c = array[y];

				stroke(c.getRed(), c.getGreen(), c.getBlue());

				int y1 = (int) ((y + (Math.sin(x
						/ (Math.PI * _analyser._averageLengthArea))
						* _analyser._crossSumDate * _analyser._monthDate)) % height);

				if (y1 < 0) {
					y1 = height + y1;
				}

				point(x, y1);
			}
		}
	}

	private void drawTanCurve() {
		Color[] array = _analyser.horizontalLine(1);

		for (int x = 0; x < width; x++) {

			double n = x / (Math.PI * _analyser._averageLengthArea);
			double b = _analyser._crossSumDate * _analyser._monthDate;

			for (int y = 0; y < height; y++) {
				Color c = array[y];

				stroke(c.getRed(), c.getGreen(), c.getBlue());

				int y1 = (int) ((y + (Math.tan(n) * b)) % height);

				if (y1 < 0) {
					y1 = height + y1;
				}

				point(x, y1);
			}
		}
	}

	private void errorPic(int pixel) {
		BufferedImage img = _analyser._image;
		int distortion = _analyser._yearDate / _analyser._dayDate;
		int currDist = 0;

		for (int y = 0; y < height; y++) {

			if (y % pixel == 0 && y != 0) {
				currDist += distortion;
			}

			for (int x = 0; x < width; x++) {
				int x1 = (x + currDist) % width;

				Color c = new Color(img.getRGB(x, y));

				stroke(c.getRed(), c.getGreen(), c.getBlue());

				point(x1, y);
			}
		}
	}

	private void drawExplosion(int pixel) {
		int cellsize = pixel % 5;
		if (cellsize == 0) {
			cellsize = 1;
		}
		PImage img; // The source image

		int columns, rows; // Number of columns and rows in our system
		img = loadImage(_analyser._startImagePath); // Load the image
		img.resize(width, height);
		columns = img.width / cellsize; // Calculate # of columns
		rows = img.height / cellsize; // Calculate # of rows

		// Begin loop for columns
		for (int i = 0; i < columns; i++) {
			// Begin loop for rows
			for (int j = 0; j < rows; j++) {
				int x = i * cellsize + cellsize / 2; // x position
				int y = j * cellsize + cellsize / 2; // y position
				int loc = x + y * img.width; // Pixel array location
				int c = img.pixels[loc]; // Grab the color
				// Calculate a z position as a function of mouseX and pixel
				// brightness
				float z = (float) (width / (width)
						* brightness(img.pixels[loc]) - 20.0);
				// Translate to the location, set fill and stroke, and draw the
				// rect
				pushMatrix();
				translate(x, y, z);
				fill(c, 204);
				noStroke();
				// rectMode(CENTER);
				rect(0, 0, cellsize, cellsize);
				popMatrix();
			}
		}
	}

	private void createTextOnGrid() {
		String textHeadline = _analyser._startHeadline.toUpperCase();
		String textSubHeadline = _analyser._startSubHeadline;
		String textTextArea = _analyser._startTextArea;
		String textDate = _analyser._startDate;

		char seperator = '\u00D7';
		String textSubConcat = textSubHeadline + " " + seperator + " "
				+ textDate;

		String fontHeadline = "SansSerif.bold";
		String fontSubHeadline = "SansSerif.plain";

		int textA = (_analyser._wordCountArea + _analyser._wordCountHead + _analyser._wordCountSub) % 3;
		textA = 0;

		switch (textA) {
		case 1:
			break;
		case 2:
			break;
		default:
			// Weisses Rechteck im Hintergrund malen

			setMaxFontSize(textTextArea, fontSubHeadline);
			int boxHeight = (int) textAscent();
			setMaxFontSize(textSubConcat, fontSubHeadline);
			boxHeight += (int) textAscent();
			setMaxFontSize(textHeadline, fontHeadline);
			boxHeight += (int) textAscent();
			boxHeight += pixel;

			while (++boxHeight % pixel != 0);

			noStroke();
			Color avgColor = _analyser.getAverageColor();
			int boxColor = 0;
			int textColor = 255;

			if (avgColor.getRed() + avgColor.getGreen() + avgColor.getBlue() < 3 * 255 / 2) {
				boxColor = 255;
				textColor = 0;
			}

			fill(boxColor, 255 / 2);
			rect(0, height - boxHeight, width, boxHeight);

			// Text ausgeben

			textAlign(CENTER);

			fill(textColor);

			setMaxFontSize(textTextArea, fontSubHeadline);
			text(textTextArea, width / 2, height - pixel, 0);

			int currentTextOffset = (int) textAscent();

			setMaxFontSize(textSubConcat, fontSubHeadline);
			text(textSubConcat, width / 2, height - pixel - currentTextOffset, 0);

			currentTextOffset += (int) textAscent();

			setMaxFontSize(textHeadline, fontHeadline);
			text(textHeadline, width / 2, height - pixel - currentTextOffset, 0);
		}
	}

	private void setMaxFontSize(String t, String font) {
		float fontSize = 0;

		do {
			fontSize += 0.5;
			textFont(createFont(font, fontSize, true));
		} while (textWidth(t) < width - (3 * pixel));
	}
}
